<script setup lang="ts">
import {Codemirror} from 'vue-codemirror';
import {json} from '@codemirror/lang-json';
import {sql} from '@codemirror/lang-sql';
import {javascript} from '@codemirror/lang-javascript';
import {java} from '@codemirror/lang-java';
import {oneDark} from '@codemirror/theme-one-dark';
import {ElMessage} from 'element-plus';
import prettier from "prettier/standalone";
import javaPlugin from "prettier-plugin-java";
import sqlPlugin from "prettier-plugin-sql";
import babelPlugin from 'prettier/plugins/babel';
import estreePlugin from 'prettier/plugins/estree';

interface Props {
  textValue?: string;
  placeholder?: string;
  language?: string;
  tabBoolean?: boolean;
  darkBoolean?: boolean;
  readOnly?: boolean;
  minWidth?: string;
  minHeight?: string;
  prettier?: boolean;
}

const props = withDefaults(defineProps<Props>(), {
  textValue: () => '',
  placeholder: () => '请输入',
  language: () => 'json',
  tabBoolean: () => true,
  darkBoolean: () => true,
  readOnly: () => false,
  minWidth: () => '100%',
  minHeight: () => '200px',
  prettier: () => false
});

// 定义选项列表
const options = [
  {value: 'json', label: 'JSON'},
  {value: 'sql', label: 'SQL'},
  {value: 'js', label: 'JavaScript'},
  {value: 'java', label: 'Java'}
];

// 内部变量
const darkBooleanValue = ref(props.darkBoolean);
const languageValue = ref(props.language);
const editorValue = ref(props.textValue);

const emit = defineEmits(['update:textValue', 'update:language', 'update:prettier']);

// 当语言改变时触发
const handleLanguageChange = () => {
  emit('update:language', languageValue.value);
  handlePrettier();
};

// 切换主题
const handleChangeTheme = () => {
  darkBooleanValue.value = !darkBooleanValue.value;
};

// 动态计算编辑器扩展
const getExtensions = (lang: string) => ({
  sql: [sql()],
  js: [javascript()],
  java: [java()],
  json: [json()]
}[lang] || []);

const getPrettierLanguage = (lang: string) => ({
  sql: 'sql',
  js: 'babel-flow',
  java: 'java',
  json: 'json-stringify'
}[lang] || []);

const getPrettierPlugin = (lang: string) => ({
  sql: [sqlPlugin],
  js: [babelPlugin,estreePlugin],
  java: [javaPlugin],
  json: [babelPlugin,estreePlugin],
}[lang] || []);

// 编辑插件
const editorExtensions = computed(() => [
  ...getExtensions(languageValue.value),
  ...(darkBooleanValue.value ? [oneDark] : [])
]);

// 当编辑器内容改变时，通知父组件
const onEditorInput = (newValue: string) => {
  emit('update:textValue', newValue);
  editorValue.value = newValue;
};

// 处理复制逻辑
const handleCopy = async () => {
  try {
    await navigator.clipboard.writeText(props.textValue);
    ElMessage({
      message: '复制成功',
      type: 'success'
    });
  } catch (err) {
    ElMessage({
      message: '复制失败，请重试',
      type: 'error'
    });
  }
};

const handlePrettier = async () => {
  const original = editorValue.value;
  const formatted = await prettier.format(editorValue.value, {
    parser: getPrettierLanguage(languageValue.value),
    plugins: getPrettierPlugin(languageValue.value),
    semi: true,
    trailingComma: 'all',
    singleQuote: true,
    printWidth: 80,
    tabWidth: 2,
  });
  if (formatted !== original) {  // 避免无变化时更新
    emit('update:textValue', formatted);
    editorValue.value = formatted;
  }
};

// 同步 textValue 和 editorValue 的值
watchEffect(() => {
  if (props.textValue !== editorValue.value) {
    editorValue.value = props.textValue;
  }
});

onMounted(() => {
  if(prettier){
    handlePrettier();
  }
})

defineExpose({
  handleCopy,
  handlePrettier
});
// todo 添加一个搜索定位功能
</script>

<template>
  <div :style="{ minWidth: props.minWidth, minHeight: props.minHeight}">
    <div class="tab-style" v-if="tabBoolean">
      <div class="tab-left">
        <el-select
          @change="handleLanguageChange"
          class="select-style"
          v-model="languageValue">
          <el-option v-for="item in options"
                     :key="item.value"
                     :label="item.label"
                     :value="item.value"></el-option>
        </el-select>
      </div>
      <div class="tab-right">
        <el-button @click="handlePrettier" circle>
          <el-icon>
            <Crop/>
          </el-icon>
        </el-button>
        <el-button @click="handleChangeTheme" circle>
          <el-icon v-show="!darkBooleanValue">
            <Sunny/>
          </el-icon>
          <el-icon v-show="darkBooleanValue">
            <Moon/>
          </el-icon>
        </el-button>
      </div>
    </div>
    <div class="editor-container" :style="{ minWidth: props.minWidth, minHeight: props.minHeight }">
      <Codemirror
        class="editor-style"
        :model-value="editorValue"
        @update:model-value="onEditorInput"
        :extensions="editorExtensions"
        :placeholder="placeholder"
        :disabled="readOnly"
        :style="{ minWidth: props.minWidth, minHeight: props.minHeight }">
      </Codemirror>
      <el-button @click="handleCopy"
                 class="editor-copy"
                 link>
        <el-icon>
          <DocumentCopy/>
        </el-icon>
        复制
      </el-button>
    </div>
  </div>
</template>

<style scoped lang="scss">
.editor-container {
  border-radius: 5px;
  overflow: hidden;
  position: relative;
}

.editor-style {
  font-family: 'Courier New', Courier, monospace;
  font-weight: bold;
  font-size: larger;
  border-radius: 1em;
}

.editor-copy {
  position: absolute;
  top: 2px;
  right: 1em;
}

.tab-style {
  display: flex;
  margin-bottom: 5px;
}

.tab-left {
  min-width: 10em
}

.tab-right {
  margin-left: auto
}

.select-style {
  width: 120px
}
</style>